home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / src / lib / mg / common / mg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-09  |  21.1 KB  |  778 lines

  1. /* Copyright (c) 1992 The Geometry Center; University of Minnesota
  2.    1300 South Second Street;  Minneapolis, MN  55454, USA;
  3.  
  4. This file is part of geomview/OOGL. geomview/OOGL is free software;
  5. you can redistribute it and/or modify it only under the terms given in
  6. the file COPYING, which you should have received along with this file.
  7. This and other related software may be obtained via anonymous ftp from
  8. geom.umn.edu; email: software@geom.umn.edu. */
  9. static char *copyright = "Copyright (C) 1992 The Geometry Center";
  10.  
  11. /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
  12.  
  13. /*
  14.  * $Id: mg.c,v 1.56 1993/09/09 22:04:19 slevy Exp $
  15.  * Machine-independent part of MG library.
  16.  * Initialization, common code, and some mgcontext maintenance.
  17.  *
  18.  * These are the common versions of MG functions (see mg.doc for
  19.  * details).  The header comment for each common function includes an
  20.  * entry labeled "DEVICE USE" which describes the way in which the
  21.  * device version of the same function is expected to call the common
  22.  * version.
  23.  *
  24.  * See mg.doc for more information about these functions.
  25.  */
  26.  
  27. #include "mgP.h"
  28.  
  29. extern struct mgfuncs mgnullfuncs;    /* Forward */
  30.  
  31. mgcontext *_mgc = NULL;
  32. mgcontext *_mgclist = NULL;
  33.  
  34. static struct mgastk *mgafree = NULL;
  35. static struct mgxstk *mgxfree = NULL;
  36.  
  37. #define    MGC    _mgc
  38.  
  39. /*
  40.  * mgcurrentcontext() returns a pointer to the currently-selected context,
  41.  * for use in a later call to mgctxselect().
  42.  * Returns NULL if no context is selected.
  43.  */
  44. mgcontext *
  45. mgcurrentcontext()
  46. {
  47.     return _mgc;
  48. }
  49.  
  50.  
  51. /*-----------------------------------------------------------------------
  52.  * Function:    mgdevice_NULL
  53.  * Description:    select the NULL device as the current MG device
  54.  * Returns:    1
  55.  * Author:    slevy (doc by mbp)
  56.  * Date:    Thu Sep 19 10:36:21 1991
  57.  * Notes:    
  58.  */
  59. int
  60. mgdevice_NULL()
  61. {
  62.     if(MGC != NULL && MGC->devno != MGD_NULL)
  63.     MGC = NULL;
  64.     _mgf = mgnullfuncs;
  65.     return 1;
  66. }
  67.  
  68. /*-----------------------------------------------------------------------
  69.  * Function:    mg_newcontext
  70.  * Description:    initialize an mgcontext structure
  71.  * Args:    mgc: ptr to context structure to initialize
  72.  * Returns:    mgc
  73.  * Author:    slevy (doc by mbp)
  74.  * Date:    Wed Sep 18 16:42:52 1991
  75.  * DEVICE USE:    required --- mgxx_ctxcreate() should call this immediately
  76.  *        after allocating a new mgcontext structure.
  77.  * Notes:    Further device-specific initialization is normally required.
  78.  */
  79. mgcontext *
  80. mg_newcontext(mgc)
  81.     register mgcontext *mgc;
  82. {
  83.     bzero((char *)mgc, sizeof(*mgc));
  84.     RefInit((Ref *)mgc, MGCONTEXTMAGIC);
  85.     mgc->shown = 1;
  86.     mgc->win = WnCreate(WN_NAME, "minnegraphics", WN_END);
  87.     mgc->cam = CamCreate( CAM_END );
  88.     mgc->background.r = 0.0;
  89.     mgc->background.g = 0.0;
  90.     mgc->background.b = 0.0;
  91.     mgc->background.a = 1.0;
  92.     {
  93.     register struct mgastk *ma;
  94.  
  95.     mgc->astk = ma = OOGLNewE(struct mgastk, "mg appearance stack");
  96.     bzero((char *)ma, sizeof(*ma));    /* Sets next = NULL, *_seq = 0 */
  97.     MtDefault(&(ma->mat));
  98.     LmDefault(&(ma->lighting));
  99.     ApDefault(&(ma->ap));
  100.     ma->ap.mat = &(ma->mat);
  101.     ma->ap.lighting = &(ma->lighting);
  102.     }
  103.     {
  104.     register struct mgxstk *mx;
  105.  
  106.     mgc->xstk = mx = OOGLNewE(struct mgxstk, "mg transform stack");
  107.     mx->next = NULL;
  108.     TmIdentity(mx->T);
  109.     mx->xfm_seq = mx->hasinv = 0;
  110.     }
  111.     mgc->opts = MGO_HIDDEN|MGO_DOUBLEBUFFER;
  112.     mgc->devno = MGD_NODEV;    /* Device-specific init should change this */
  113.  
  114.     TmIdentity(mgc->W2C); TmIdentity(mgc->C2W);
  115.     TmIdentity(mgc->W2S); TmIdentity(mgc->S2W);
  116.     TmIdentity(mgc->O2S); TmIdentity(mgc->S2O);
  117.  
  118.     TmIdentity(mgc->T4);
  119.     mgc->T4_seq = 0;
  120.  
  121.     mgc->space = TM_EUCLIDEAN;
  122.  
  123.     mgc->NDinfo = NULL;
  124.     VVINIT(mgc->point, HPoint3, 7);
  125.  
  126.     mgc->next = _mgclist;
  127.     _mgclist = mgc;
  128.  
  129.     return mgc;
  130. }
  131.  
  132. int
  133. mg_appearancebits( Appearance *ap, int mergeflag, int *valid, int *flag )
  134. {
  135.   register Appearance *dst;
  136.  
  137.   if (!_mgc->astk) {
  138.     OOGLError(0,"mg_appearanceflags: no global context");
  139.     return 0;
  140.   }
  141.   dst = &(_mgc->astk->ap);
  142.  
  143.   /* Mask of fields to change in dst */  
  144.   if (ap == NULL) {
  145.     *valid = dst->valid;
  146.     *flag = dst->flag;
  147.     mergeflag = MG_MERGE;
  148.   } else {
  149.     *valid = ap->valid;
  150.     *flag = ap->flag;
  151.   }
  152.   if (mergeflag == MG_MERGE) {
  153.     *valid &= ~dst->override;
  154.   }
  155.   return 1;
  156. }
  157.  
  158. /*-----------------------------------------------------------------------
  159.  * Function:    mg_identity
  160.  * Description:    Set the current object xform to the identity
  161.  * Args:    (none)
  162.  * Returns:    nothing
  163.  * Author:    slevy (doc by mbp)
  164.  * Date:    Wed Sep 18 16:46:06 1991
  165.  * Notes:    Sets the xform on the top of the current context's xform
  166.  *        stack to the identity.  Also sets the MC_TRANS bit of
  167.  *        the context's "changed" flag and increment's the current xfm
  168.  *        sequence number.
  169.  * DEVICE USE:  optional --- if the device actually uses the context
  170.  *        structure's xform stack, call this to do the work.  If
  171.  *        the device keeps its own stack, it doesn't have to call
  172.  *        this.
  173.  */
  174. void
  175. mg_identity( void )
  176. {
  177.     TmIdentity(_mgc->xstk->T);
  178.     _mgc->changed |= MC_TRANS;
  179.     _mgc->xstk->xfm_seq++;
  180. }
  181.  
  182. /*-----------------------------------------------------------------------
  183.  * Function:    mg_settransform
  184.  * Description:    Set the current object xform
  185.  * Args:    T
  186.  * Returns:    nothing
  187.  * Author:    slevy (doc by mbp)
  188.  * Date:    Wed Sep 18 16:46:06 1991
  189.  * Notes:    Sets the xform on the top of the current context's xform
  190.  *        stack to T.  Also sets the MC_TRANS bit of
  191.  *        the context's "changed" flag and increment's the current xfm
  192.  *        sequence number.
  193.  * DEVICE USE:  optional --- if the device actually uses the context
  194.  *        structure's xform stack, call this to do the work.  If
  195.  *        the device keeps its own stack, it doesn't have to call
  196.  *        this.
  197.  */
  198. void
  199. mg_settransform( Transform T )
  200. {
  201.     TmCopy(T, _mgc->xstk->T);
  202.     _mgc->changed |= MC_TRANS;
  203.     _mgc->xstk->xfm_seq++;
  204. }
  205.  
  206. /*-----------------------------------------------------------------------
  207.  * Function:    mg_gettransform
  208.  * Description:    Get the current object xform
  209.  * Args:    T
  210.  * Returns:    nothing
  211.  * Author:    slevy (doc by mbp)
  212.  * Date:    Wed Sep 18 16:46:06 1991
  213.  * Notes:    Writes the current object xform, from the top of the
  214.  *        context's xform stack, into T.
  215.  * DEVICE USE:  optional --- if the device actually uses the context
  216.  *        structure's xform stack, call this to do the work.  If
  217.  *        the device keeps its own stack, it doesn't have to call
  218.  *        this.
  219.  */
  220. void
  221. mg_gettransform( Transform T )
  222. {
  223.     TmCopy(_mgc->xstk->T, T);
  224. }
  225.  
  226. /*-----------------------------------------------------------------------
  227.  * Function:    mg_transform
  228.  * Description:    premultiply the current object xform by a transform
  229.  * Args:    T: the transform to premultiply by
  230.  * Returns:    nothing
  231.  * Author:    slevy (doc by mbp)
  232.  * Date:    Wed Sep 18 16:46:06 1991
  233.  * Notes:    If X is the context's current object xform, replaces X
  234.  *        by T X.
  235.  * DEVICE USE:  optional --- if the device actually uses the context
  236.  *        structure's xform stack, call this to do the work.  If
  237.  *        the device keeps its own stack, it doesn't have to call
  238.  *        this.
  239.  */
  240. void
  241. mg_transform( Transform T )
  242. {
  243.     TmConcat(T, _mgc->xstk->T, _mgc->xstk->T);
  244.     _mgc->changed |= MC_TRANS;
  245.     _mgc->xstk->xfm_seq++;
  246.     _mgc->xstk->hasinv = 0;
  247. }
  248.  
  249. /*-----------------------------------------------------------------------
  250.  * Function:    mg_pushappearance
  251.  * Description:    push the context's appearance stack
  252.  * Returns:    nothing
  253.  * Author:    slevy (doc by mbp)
  254.  * Date:    Thu Sep 19 10:37:55 1991
  255.  * Notes:    
  256.  * DEVICE USE:    required --- all devices must maintain this stack
  257.  */
  258. int
  259. mg_pushappearance()
  260. {
  261.     register struct mgastk *ma;
  262.  
  263.     if(mgafree) ma = mgafree, mgafree = ma->next;
  264.     else ma = OOGLNew(struct mgastk);
  265.     *ma = *_mgc->astk;
  266.     ma->next = _mgc->astk;
  267.     ma->lighting.lights = LtCopylist(_mgc->astk->lighting.lights,1);
  268.     ma->ap.lighting = &(ma->lighting);
  269.     ma->ap.mat = &(ma->mat);
  270.     _mgc->astk = ma;
  271. }
  272.  
  273. /*-----------------------------------------------------------------------
  274.  * Function:    mg_popappearance
  275.  * Description:    pop the context's appearance stack
  276.  * Returns:    nothing
  277.  * Author:    slevy (doc by mbp)
  278.  * Date:    Thu Sep 19 10:51:12 1991
  279.  * Notes:    
  280.  * DEVICE USE:    required --- all deviced must maintain this stack
  281.  */
  282. int
  283. mg_popappearance()
  284. {
  285.     register struct mgastk *mp;
  286.     register struct mgcontext *ms = _mgc;
  287.  
  288.     mp = ms->astk->next;
  289.     if(mp == NULL)
  290.     return -1;
  291.     if(ms->astk->ap_seq != mp->ap_seq) ms->changed |= MC_AP;
  292.     if(ms->astk->mat_seq != mp->mat_seq) ms->changed |= MC_MAT;
  293.     if(ms->astk->light_seq != mp->light_seq) ms->changed |= MC_LIGHT;
  294.     LtDeletelist(ms->astk->lighting.lights);
  295.     ms->astk->next = mgafree; mgafree = ms->astk;
  296.     ms->astk = mp;
  297.     return 0;
  298. }
  299.  
  300. /*
  301.  * Transform light(s) to global coordinate system, if they aren't already.
  302.  * Transforms them in place; this is safe, since mg keeps a private copy of
  303.  * the light structures.
  304.  */
  305. void
  306. mg_globallights( LtLight *lights, int worldbegin )
  307. {
  308.     LtLight *lt;
  309.  
  310.     for(lt = lights; lt != NULL; lt = lt->next) {
  311.     switch(lt->location) {
  312.     case LTF_GLOBAL:
  313.         lt->globalposition = lt->position;
  314.         break;
  315.     case LTF_CAMERA:
  316.         HPt3Transform(_mgc->C2W, <->position, <->globalposition);
  317.         if (worldbegin) lt->changed = 1;
  318.         break;
  319.     case LTF_LOCAL:
  320.         HPt3Transform(_mgc->xstk->T, <->position, <->position);
  321.         lt->globalposition = lt->position;
  322.         lt->location = LTF_GLOBAL;
  323.         if (worldbegin) lt->changed = 1;
  324.         break;
  325.     }
  326.     }
  327. }
  328.  
  329. /*-----------------------------------------------------------------------
  330.  * Function:    mg_setappearance
  331.  * Description:    Operate on appearance in current context
  332.  * Args:    *ap: the appearance to assign or merge
  333.  *        mergeflag: MG_MERGE or MG_SET
  334.  * Returns:    ptr to current appearance
  335.  * Author:    slevy (doc by mbp)
  336.  * Date:    Thu Sep 19 10:59:25 1991
  337.  * Notes:    Modifies the context's current apperance.  Does not
  338.  *        modify *ap.
  339.  *          mergeflag = MG_MERGE: merge *ap into current appearance
  340.  *          mergeflag = MG_SET: set current appearance to *ap
  341.  * DEVICE USE:  required --- when ???
  342.  *
  343.  *        Can we modify this to do some of the flag setting
  344.  *        than mggl_setappearance currently does???  This
  345.  *        seems common to all devices.
  346.  */
  347. Appearance *
  348. mg_setappearance( Appearance *ap, int mergeflag )
  349. {
  350.     register Appearance *nap;
  351.     register struct mgastk *ma = _mgc->astk;
  352.  
  353.     if(mergeflag == MG_MERGE) {
  354.     nap = ApMerge(ap, &ma->ap, 1);    /* Merge, in place */
  355.     ma->changed |= MC_AP;
  356.     ma->ap = *nap;
  357.     /* Assign mat and light too? */
  358.     } else {
  359.     ApCopy(ap, &ma->ap);
  360.     ma->changed |= MC_AP | MC_MAT | MC_LIGHT;
  361.     }
  362.     if(ap->lighting)
  363.     mg_globallights(ma->lighting.lights, 0);
  364.     return &_mgc->astk->ap;
  365. }
  366.  
  367. /*-----------------------------------------------------------------------
  368.  * Function:    mg_getappearance
  369.  * Description:    get the current appearance
  370.  * Returns:    ptr to the current appearance
  371.  * Author:    slevy (doc by mbp)
  372.  * Date:    Thu Sep 19 11:08:06 1991
  373.  * DEVICE USE:    optional
  374.  * Notes:    The pointer returned points to the context's private copy
  375.  *        of the appearance.  Don't modify it!
  376.  *
  377.  *        Should we allow this?  Or should this copy the appearance
  378.  *        to an address passed as an argument ???
  379.  */
  380. Appearance *
  381. mg_getappearance()
  382. {
  383.   return( &(_mgc->astk->ap) );
  384. }
  385.  
  386.  
  387. /*-----------------------------------------------------------------------
  388.  * Function:    mg_setcamera
  389.  * Description:    Set the context's camera
  390.  * Args:    *cam: the camera to use
  391.  * Returns:    nothing
  392.  * Author:    slevy (doc by mbp)
  393.  * Date:    Thu Sep 19 11:16:46 1991
  394.  * Notes:    The context does not maintain an internal copy of the
  395.  *        camera.  Only the pointer is stored.
  396.  * DEVICE USE:  required
  397.  */
  398. int
  399. mg_setcamera( Camera *cam )
  400. {
  401.   RefIncr((Ref *)cam); /* Incr count first: allow setting same camera */
  402.   CamDelete(_mgc->cam);
  403.   _mgc->cam = cam;
  404.   _mgc->changed |= MC_CAM;
  405. }
  406.  
  407. /*-----------------------------------------------------------------------
  408.  * Function:    mg_ctxset
  409.  * Description:    set some attributes in the current context
  410.  * Args:    attr, ...: list of attribute-value pairs, terminated
  411.  *          by MG_END
  412.  * Returns:    nothing
  413.  * Author:    slevy (doc by mbp)
  414.  * Date:    Thu Sep 19 11:22:28 1991
  415.  * Notes:    DO NOT CALL THIS (yet)!  It currently does nothing.
  416.  * DEVICE USE:  forbidden --- devices have their own mgxx_ctxset()
  417.  *
  418.  *        This needs to be modified to work as the NULL device.
  419.  *        Use by other devices may never be needed.
  420.  */
  421. void
  422. mg_ctxset( int attr, ... /*, MG_END */ )
  423. {}
  424.  
  425.  
  426. /*-----------------------------------------------------------------------
  427.  * Function:    mg_ctxget
  428.  * Description:    get an attribute from the current context
  429.  * Args:    attr: the attribute to get
  430.  *        *valuep: place to write attr's value
  431.  * Returns:    ???
  432.  * Author:    slevy (doc by mbp)
  433.  * Date:    Thu Sep 19 11:26:49 1991
  434.  * Notes:    DO NOT CALL THIS (yet)!  It currently does nothing.
  435.  * DEVICE USE:  forbidden --- devices have their own mgxx_ctxget()
  436.  *
  437.  *        This needs to be modified to work as the NULL device.
  438.  *        Use by other devices may never be needed.
  439.  */
  440. int
  441. mg_ctxget( int attr, void *valuep )
  442. {
  443.   return -1;
  444. }
  445.  
  446.  
  447. /*-----------------------------------------------------------------------
  448.  * Function:    mg_feature
  449.  * Description:    determine whether the NULL device has a particular feature
  450.  * Args:    feature: feature to test for
  451.  * Returns:    -1 (means feature is not present)
  452.  * Author:    slevy (doc by mbp)
  453.  * Date:    Thu Sep 19 11:29:51 1991
  454.  * Notes:    NULL device is rather featureless at present, :-)
  455.  * DEVICE USE:  forbidden --- devices have their own mgxx_feature()
  456.  */
  457. int
  458. mg_feature( int feature )
  459. {
  460.   return -1;
  461. }
  462.  
  463. /*-----------------------------------------------------------------------
  464.  * Function:    mg_ctxcreate
  465.  * Description:    create a new MG context for the NULL device
  466.  * Args:    a1, ...: list of attribute-value pairs
  467.  * Returns:    ptr to new context
  468.  * Author:    mbp
  469.  * Date:    Thu Sep 19 11:35:42 1991
  470.  * Notes:    DO NOT CALL THIS --- it currently does nothing
  471.  *        needs to be modified to work with NULL device ???
  472.  * DEVICE USE:  forbidden --- devices have their own mgxx_ctxcreate(()
  473.  */
  474. mgcontext *
  475. mg_ctxcreate( int a1, ... )
  476. {
  477.   return NULL;
  478. }
  479.  
  480. /*-----------------------------------------------------------------------
  481.  * Function:    mg_ctxdelete
  482.  * Description:    delete an MG context for the NULL device
  483.  * Args:    *ctx: ptr to context to delete
  484.  * Returns:    nothing
  485.  * Author:    mbp
  486.  * Date:    Thu Sep 19 11:38:50 1991
  487.  * Notes:    DO NOT CALL THIS --- it currently does nothing
  488.  *        needs to be modified to work with NULL device ???
  489.  * DEVICE USE:  forbidden --- devices have their own mgxx_ctxdelete()
  490.  */
  491. void
  492. mg_ctxdelete( mgcontext *ctx )
  493. {
  494.     register struct mgcontext **mp;
  495.  
  496.     if(ctx == NULL)
  497.     return;
  498.     for(mp = &_mgclist; *mp != NULL; mp = &(*mp)->next) {
  499.     if(*mp == ctx) {
  500.         *mp = ctx->next;
  501.         break;
  502.     }
  503.     }
  504.     /* Free other data here someday XXX */
  505.     OOGLFree(ctx);
  506. }
  507.  
  508. /*-----------------------------------------------------------------------
  509.  * Function:    mg_ctxselect
  510.  * Description:    select the current context
  511.  * Args:    *ctx: the context to select
  512.  * Returns:    0 (why ???)
  513.  * Author:    slevy (doc by mbp)
  514.  * Date:    Thu Sep 19 11:40:15 1991
  515.  * DEVICE USE:  required --- mgxx_ctxselect() should call this if
  516.  *        the context to switch to if of a different device.
  517.  *        This procedure then does the switch.
  518.  */
  519. int
  520. mg_ctxselect( mgcontext *ctx )
  521. {
  522.    if(ctx != NULL && _mgf.mg_devno != ctx->devno) {
  523.     /*
  524.      * For another device.
  525.      * Install that device's function pointers, and
  526.      * call its selectcontext routine.
  527.      */
  528.     (*ctx->devfuncs->mg_setdevice)();
  529.     mgctxselect(ctx);
  530.    }
  531.    _mgc = ctx;
  532.    return 0;
  533. }
  534.  
  535. /*-----------------------------------------------------------------------
  536.  * Function:    mg_pushtransform
  537.  * Description:    push the context xform stack
  538.  * Returns:    nothing
  539.  * Author:    mbp
  540.  * Date:    Thu Sep 19 12:23:26 1991
  541.  * DEVICE USE:    optional --- use if device actually uses our stack
  542.  */
  543. int
  544. mg_pushtransform( void )
  545. {
  546.   register struct mgxstk *xfm;
  547.   if(mgxfree) xfm = mgxfree, mgxfree = xfm->next;
  548.   else xfm = OOGLNewE(struct mgxstk, "mgpushtransform");
  549.   *xfm = *MGC->xstk;
  550.   xfm->next = MGC->xstk;
  551.   MGC->xstk = xfm;
  552. }
  553.  
  554. /*-----------------------------------------------------------------------
  555.  * Function:    mg_poptransform
  556.  * Description:    pop the context xform stack
  557.  * Returns:    nothing
  558.  * Author:    mbp
  559.  * Date:    Thu Sep 19 12:23:51 1991
  560.  * DEVICE USE:    optional --- use if device actually uses our stack
  561.  */
  562. int
  563. mg_poptransform( void )
  564. { register struct mgxstk *xfm = MGC->xstk;
  565.   if(xfm->next == NULL)
  566.     return -1;
  567.   MGC->xstk = xfm->next;
  568.   xfm->next = mgxfree;
  569.   mgxfree = xfm;
  570.   _mgc->has = 0;
  571. }
  572.  
  573.  
  574. /*
  575.  * Handle 4D->3D transform
  576.  * This allows the drawing routines to compute normals on 4D objects
  577.  * by knowing how they'll appear in 3D, and also to know whether
  578.  * the calculation must be redone (because the 4D->3D transform changed
  579.  * since the normals were last computed).  This transform doesn't really
  580.  * belong in the mg state, but the drawing routines need it, so this is the
  581.  * natural place to put the data.
  582.  */
  583. mgset4to3( Transform T, int seq )
  584. {
  585.     TmCopy(T, MGC->T4);
  586.     MGC->T4_seq = seq;
  587. }
  588.  
  589. int
  590. mgget4to3( Transform T )
  591. {
  592.     TmCopy(MGC->T4, T);
  593.     return MGC->T4_seq;
  594. }
  595.  
  596. void
  597. mg_sync( void )
  598. {}
  599.  
  600. void
  601. mg_worldbegin( void )
  602. {
  603.   Transform S, V;
  604.   WnPosition vp;
  605.  
  606.   CamGet(_mgc->cam, CAM_W2C, _mgc->W2C);
  607.   CamGet(_mgc->cam, CAM_C2W, _mgc->C2W);
  608.   CamView(_mgc->cam, V);
  609.   WnGet(_mgc->win, WN_VIEWPORT, &vp);
  610.     /* V maps world to [-1..1],[-1..1],[-1..1] */
  611.   TmTranslate(S, 1., 1., 0.);
  612.   TmConcat(V, S, V); /* now maps to [0..2],[0..2],[-1..1] */
  613.   TmScale(S, .5*(vp.xmax-vp.xmin+1), .5*(vp.ymax-vp.ymin+1), 1.);
  614.             /* now maps to [0..xsize],[0..ysize],[-1..1] */
  615.   TmConcat(V, S, _mgc->W2S);    /* final world-to-screen matrix */
  616.   TmInvert(_mgc->W2S, _mgc->S2W);    /* and screen-to-world */
  617.   TmCopy(_mgc->W2S, _mgc->O2S);
  618.   TmCopy(_mgc->S2W, _mgc->S2O);
  619.   TmIdentity(_mgc->xstk->T);
  620.   _mgc->xstk->hasinv = 0;
  621.   _mgc->has |= HAS_S2O;
  622. }
  623.  
  624. void
  625. mg_findO2S()
  626. {
  627.     TmConcat(_mgc->xstk->T, _mgc->W2S, _mgc->O2S);
  628. }
  629.  
  630. void
  631. mg_findS2O()
  632. {
  633.   if(!(_mgc->has & HAS_S2O)) {
  634.     if(!_mgc->xstk->hasinv) {
  635.     TmInvert(_mgc->xstk->T, _mgc->xstk->Tinv);
  636.     _mgc->xstk->hasinv = 1;
  637.     }
  638.     TmConcat(_mgc->S2W, _mgc->xstk->Tinv, _mgc->S2O);
  639.     TmConcat(_mgc->xstk->T, _mgc->W2S, _mgc->O2S);
  640.     _mgc->has |= HAS_S2O;
  641.   }
  642. }
  643.  
  644. /* Construct a prototype polygonal outline for creating fat points.
  645.  * Curiously, we can do this independently of the position of the point,
  646.  * if we operate in homogeneous space.
  647.  */
  648. void mg_makepoint()
  649. {
  650.   int i, n;
  651.   float t, r, c, s;
  652.   register HPoint3 *p;
  653.   static float nsides = 3.0;
  654.  
  655.   if(!(_mgc->has & HAS_S2O))
  656.     mg_findS2O();
  657.  
  658.   if(_mgc->astk->ap.linewidth <= 3) n = 4;
  659.   else n = nsides * sqrt((double)_mgc->astk->ap.linewidth);
  660.   vvneeds(&_mgc->point, n);
  661.   VVCOUNT(_mgc->point) = n;
  662.   r = _mgc->astk->ap.linewidth;
  663.   for(i = 0, p = VVEC(_mgc->point, HPoint3);  i < n;  i++, p++) {
  664.     t = 2*M_PI*i/n; s = r * sin(t); c = r * cos(t);
  665.     p->x = _mgc->S2O[0][0]*c + _mgc->S2O[1][0]*s;
  666.     p->y = _mgc->S2O[0][1]*c + _mgc->S2O[1][1]*s;
  667.     p->z = _mgc->S2O[0][2]*c + _mgc->S2O[1][2]*s;
  668.     p->w = _mgc->S2O[0][3]*c + _mgc->S2O[1][3]*s;
  669.   }
  670.   _mgc->has |= HAS_POINT;
  671. }
  672.  
  673. void
  674. mg_findcam()
  675. {
  676.   Transform inv;
  677.   /*
  678.    * Figure out where the camera is in the current coordinate system
  679.    */
  680.   if(!_mgc->xstk->hasinv) {
  681.     TmInvert(_mgc->xstk->T, _mgc->xstk->Tinv);
  682.     _mgc->xstk->hasinv = 1;
  683.   }
  684.   HPt3TransPt3(_mgc->xstk->Tinv, &_mgc->C2W[3][0], &_mgc->cpos);
  685.   _mgc->has |= HAS_CPOS;
  686. }
  687.  
  688. void
  689. mg_worldend( void )
  690. {}
  691.  
  692. void
  693. mg_reshapeviewport( void )
  694. {}
  695.  
  696. void
  697. mg_polygon( int nv, Point3 *v, int nn,
  698.          Point3 *n, int nc,ColorA *c )
  699. {}
  700.  
  701.  
  702. void
  703. mg_polylist()
  704. {}
  705.  
  706.  
  707. void
  708. mg_mesh( int wrap,int nu,int nv, HPoint3 *p,
  709.       Point3 *n,ColorA *c )
  710. {}
  711.  
  712. void
  713. mg_line( HPoint3 *p1, HPoint3 *p2 )
  714. {}
  715.  
  716. void
  717. mg_polyline( int nv, HPoint3 *verts,
  718.           int nc, ColorA *colors )
  719. {}
  720.  
  721. void
  722. mg_quads( int nquads, HPoint3 *verts, Point3 *normals, ColorA *colors )
  723. {
  724.     int i;
  725.     HPoint3 *v = verts;
  726.     Point3 *n = normals;
  727.     ColorA *c = colors;
  728.     int dn = normals ? 4 : 0;
  729.     int dc = colors ? 4 : 0;
  730.     
  731.     for(i = 0; i < nquads; i++, v += 4, n += dn, c += dc)
  732.     mgpolygon(4, v, dn, n, dc, c);
  733. }
  734.  
  735. void
  736. mg_bezier(int du, int dv, int dimn, float *ctrlpts, float *txmapst, ColorA *c)
  737. {
  738. }
  739.  
  740. #define NULLFUNCS {                    \
  741.     MGD_NODEV,                    \
  742.     mgdevice_NULL,        /* mg_setdevice           */ \
  743.     mg_feature,        /* mg_feature           */ \
  744. (mgcontext *(*)())mg_ctxcreate,        /* mg_ctxcreate           */ \
  745.     mg_ctxdelete,        /* mg_ctxdelete           */ \
  746. (void (*)())mg_ctxset,        /* mg_ctxset           */ \
  747.     mg_ctxget,        /* mg_ctxget           */ \
  748.     mg_ctxselect,        /* mg_ctxselect           */ \
  749.     mg_sync,        /* mg_sync           */ \
  750.     mg_worldbegin,        /* mg_worldbegin       */ \
  751.     mg_worldend,        /* mg_worldend           */ \
  752.     mg_reshapeviewport,    /* mg_reshapeviewport  */ \
  753.     mg_settransform,    /* mg_settransform     */ \
  754.     mg_gettransform,    /* mg_gettransform     */ \
  755.     mg_identity,        /* mg_identity           */ \
  756.     mg_transform,        /* mg_transform           */ \
  757.     mg_pushtransform,    /* mg_pushtransform    */ \
  758.     mg_poptransform,    /* mg_poptransform     */ \
  759.     mg_pushappearance,    /* mg_pushappearance   */ \
  760.     mg_popappearance,    /* mg_popappearance    */ \
  761.     mg_setappearance,    /* mg_setappearance    */ \
  762.     mg_getappearance,    /* mg_getappearance    */ \
  763.     mg_setcamera,        /* mg_setcamera           */ \
  764.     mg_polygon,        /* mg_polygon           */ \
  765.     mg_polylist,        /* mg_polylist           */ \
  766.     mg_mesh,        /* mg_mesh           */ \
  767.     mg_line,        /* mg_line           */ \
  768.     mg_polyline,        /* mg_polyline           */ \
  769.     mg_quads,        /* mg_quads           */ \
  770.     mg_bezier,        /* mg_bezier */        \
  771.     }
  772.  
  773. struct mgfuncs mgnullfuncs =    /* mgfuncs for null (default) output device */
  774.   NULLFUNCS;
  775.  
  776. struct mgfuncs _mgf = NULLFUNCS;
  777.  
  778.